package avicit.bdp.dcs.threshold.base;

import avicit.bdp.common.utils.DateUtils;
import avicit.bdp.dcs.alert.dto.AlertDTO;
import avicit.bdp.dcs.detail.dto.DataDetailDto;
import avicit.bdp.dcs.detail.dto.TableDetailDto;
import avicit.bdp.dcs.job.dto.JobDTO;
import avicit.bdp.dcs.threshold.utils.TestUtils;
import avicit.platform6.core.rest.msg.ResponseMsg;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;

/**
 * 数据同步测试用例
 */
public class DataSyncTest {

    private RestTemplate restTemplate = new RestTemplate();

    private String jobName = "数据同步门槛用例";

    private static String srcTble = "ds_src_" + System.currentTimeMillis();

    private static String dstTble = "ds_dst_" + System.currentTimeMillis();

    /**
     * 所有用例执行前准备工作
     */
    @BeforeClass
    public static void init() {
        System.out.println("数据同步门槛用例用例初始化...");
        TestUtils.insert2Mysql(srcTble);
    }

    /**
     * 单个测试用例运行前准备工作
     */
    @Before
    public void setUp() {
        // TODO:
    }

    /**
     * 单个测试用例运行后销毁工作
     */
    @After
    public void tearDown() {
        // TODO:
    }

    /**
     * 所有用例执行完成后准备工作
     */
    @AfterClass
    public static void destory() {
        System.out.println("数据同步门槛用例用例执行完成，开始清理...");
        TestUtils.deleteFromMysql(srcTble);
        TestUtils.deleteFromMysql(dstTble);
    }

    /***********************************************Begin 测试用例 ***********************************************/
    /**
     * 测试数据同步
     *
     * @throws Exception
     */
    @Test(timeout = 5 * 60 * 1000)
    public void testDataSync() throws Exception {
        // step1:保存数据源
        ResponseEntity<ResponseMsg> result = restTemplate.postForEntity(TestUtils.HOSTPORT
                        + "/api/bdp/dcs/job/JobRest/saveDataSource", TestUtils.buildSaveDataSourceParas(2,
                jobName, TestUtils.MYSQL_SRC_DATASOURCE_ID, TestUtils.MYSQL_DST_DATASOURCE_ID, 1),
                ResponseMsg.class);
        TestUtils.handleFailedRequest(result);
        assertEquals("200", result.getBody().getRetCode());
        // 获取创建的JobId
        ResponseMsg responseMsg = result.getBody();
        Map<String, String> jobMap = (Map<String, String>) responseMsg.getResponseBody();
        String jobId = jobMap.get("jobId");

        try {
            // step2:保存表映射关系
            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/saveTableMapping",
                    TestUtils.buildSaveTblMapping(2, jobId, srcTble, dstTble), ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step3:任务配置检查
            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/checkTaskConfig",
                    TestUtils.buildCheckTaskConfig(jobId), ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step4:预检查
            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/precheck/PrecheckRest/executePrecheck",
                    TestUtils.buildPreChecks(jobId), ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step5:更新Job状态
            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/updateJobStatus",
                    TestUtils.buildUpdateJobStatus(jobId), ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step6:启用/禁用Job
            //        buildReleaseJob();
            //        result = restTemplate.exchange(HOSTPORT + "/api/bdp/dcs/job/JobRest/releaseJob?jobId="+JOBID+"&enable=1",
            //                HttpMethod.GET, httpReleaseJobEntity, ResponseMsg.class);
            //        assertEquals("200", result.getBody().getRetCode());

            // step7:启动任务
            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/startJobByIds?jobIds=" + jobId,
                            TestUtils.buildStartJob(jobId), ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step8:获取Job列表
            // 等待DS启动任务成功
            Thread.sleep(40 * 1000);
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/getJobList" +
                            "?jobStatus&sort&name=数据同步门槛用例&jobType=1&currentPage=1&pageSize=10",
                    HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);
            ResponseMsg body = result.getBody();
            LinkedHashMap<String, Object> map = (LinkedHashMap<String, Object>) body.getResponseBody();
            List<Object> finalBody = (List<Object>) map.get("result");
            for (Object obj : finalBody) {
                LinkedHashMap<String, String> jobObj = (LinkedHashMap<String, String>) obj;
                JobDTO jobInfo = JSON.parseObject(JSON.toJSONString(jobObj), JobDTO.class);
                // 判断任务是否启动成功；
                if (jobInfo.getId().equals(jobId)) {
                    System.out.println("数据同步门槛用例任务状态:" + jobInfo.getJobStatus());

                    // 判断任务是否同步完成;
                    assertEquals(7 == jobInfo.getJobStatus(), true);

                    // 判断同步速度;（备注：源表中只有一行数据，大小固定）
                    assertEquals(jobInfo.getReadSucceedBytes() == 18, true);

                    break;
                }
            }

            // step9:查看日志信息
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/log/LogRest/getLogByTaskId" +
                    "?taskInstanceId=&skipLineNum=0" +
                    "&limit=100&jobId=" + jobId, HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);
            assertEquals("200", result.getBody().getRetCode());

            // step10:查看详情，包括表结构迁移、数据迁移；
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/detail/TaskTableDetailRest" +
                            "/getTaskTableDetailList" +
                            "?currentPage=1&pageSize=20&srcTableName=&jobId=" + jobId, HttpMethod.GET,
                    TestUtils.buildGetHttpEntity(),
                    ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            body = result.getBody();
            map = (LinkedHashMap<String, Object>) body.getResponseBody();
            finalBody = (List<Object>) map.get("result");
            for (Object obj : finalBody) {
                LinkedHashMap<String, String> jobObj = (LinkedHashMap<String, String>) obj;
                TableDetailDto tableDetailDto = JSON.parseObject(JSON.toJSONString(jobObj), TableDetailDto.class);
                // 判断任务是否同步迁移完成;
                assertEquals(7 == tableDetailDto.getTaskStatus(), true);
            }

            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/detail/TaskDataDetailRest" +
                            "/getTaskDataDetailList" +
                            "?currentPage=1&pageSize=20&srcTableName=&jobId=" + jobId, HttpMethod.GET,
                    TestUtils.buildGetHttpEntity(), ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());
            body = result.getBody();
            map = (LinkedHashMap<String, Object>) body.getResponseBody();
            finalBody = (List<Object>) map.get("result");
            for (Object obj : finalBody) {
                LinkedHashMap<String, String> jobObj = (LinkedHashMap<String, String>) obj;
                DataDetailDto dataDetailDto = JSON.parseObject(JSON.toJSONString(jobObj), DataDetailDto.class);
                // 判断任务是否task是否处于“同步完成”
                assertEquals(7 == dataDetailDto.getTaskStatus(), true);

                // 判断预估总数是否为2条；
                assertEquals(dataDetailDto.getEstimateTotal() == 2, true);

                // 判断已完成总数是否为2条；
                assertEquals(dataDetailDto.getCompletedTotal() == 2, true);
            }

            // step11:查看作业详情
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/getJobDetail?" +
                    "jobId=" + jobId, HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);
            assertEquals("200", result.getBody().getRetCode());

            body = result.getBody();
            map = (LinkedHashMap<String, Object>) body.getResponseBody();
            String srcDatasourceId = (String) map.get("srcDatasourceId");
            assertEquals(TestUtils.MYSQL_SRC_DATASOURCE_ID, srcDatasourceId);

            // step12:查看任务执行历史
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/getHistoryJobList?" +
                    "jobId=" + jobId, HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);
            assertEquals("200", result.getBody().getRetCode());

            body = result.getBody();
            map = (LinkedHashMap<String, Object>) body.getResponseBody();
            finalBody = (List<Object>) map.get("result");
            assertEquals(1, finalBody.size());

            // step13:监控报警设置
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/alert/AlertRest/getAlertListByJobId?jobId="+jobId,
                    HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);

            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            finalBody = (List<Object>) result.getBody().getResponseBody();
            assertEquals(1, finalBody.size());

            LinkedHashMap<String, String> alertObj = (LinkedHashMap<String, String>) finalBody.get(0);
            AlertDTO alertDTO = JSON.parseObject(JSON.toJSONString(alertObj), AlertDTO.class);

            // 修改报警
            JSONObject param = new JSONObject();
            param.put("id", alertDTO.getId());
            param.put("alertRule", 6);
            param.put("userIds", "1");

            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/alert/AlertRest/updateAlert",
                    TestUtils.buildPostHttpEntity(param.toJSONString()), ResponseMsg.class);

            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step14:查看同步性能
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/task/TaskRest/getTableListByJobId?jobId="+jobId+"&syncMode=1",
                    HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);

            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            finalBody = (List<Object>) result.getBody().getResponseBody();
            assertEquals(1, finalBody.size());

            LinkedHashMap<String, String> obj = (LinkedHashMap<String, String>) finalBody.get(0);
            String taskId = obj.get("id");

            // 查询同步性能
            String startTime = DateUtils.getTodayStartTime();
            String endTime = DateUtils.getTodayEndTime();
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/log/LogRest/getPerformanceByTaskId?taskId="+taskId+"&startTime="+startTime+"&endTime="+endTime,
                    HttpMethod.GET, TestUtils.buildGetHttpEntity(), ResponseMsg.class);

            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // step15:配置定时管理
            JSONObject param0 = new JSONObject();
            param0.put("crontab", "0 30 2 * * ?");
            param0.put("endTime", endTime);
            param0.put("failureStrategy", 0);
            param0.put("isQuartzCron", 0);
            param0.put("processDefinitionId", jobId);
            param0.put("processInstancePriority", 0);
            param0.put("startTime", startTime);
            param0.put("warningType", 0);
            param0.put("warningUserIds", "");

            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/saveSchedule",
                    TestUtils.buildPostHttpEntity(param0.toJSONString()), ResponseMsg.class);

            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

            // 启用定时
            JSONObject param1 = new JSONObject();
            param1.put("enable", 1);
            param1.put("id", jobId);
            result = restTemplate.postForEntity(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/releaseJob",
                    TestUtils.buildPostHttpEntity(param1.toJSONString()), ResponseMsg.class);

            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());

        } finally {
            // step16:删除job
            result = restTemplate.exchange(TestUtils.HOSTPORT + "/api/bdp/dcs/job/JobRest/deleteJobByIds",
                    HttpMethod.DELETE,
                    TestUtils.buildDeleteJob(jobId),
                    ResponseMsg.class);
            TestUtils.handleFailedRequest(result);
            assertEquals("200", result.getBody().getRetCode());
        }
    }

}
